package com.wzcl.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.wzcl.app.dao.model.Activity;
import com.wzcl.app.dao.model.Grade;
import com.wzcl.app.dao.model.KnowledgePoint;
import com.wzcl.app.dao.model.Subject;
import com.wzcl.app.dao.repository.KnowledgePointRepository;
import com.wzcl.app.model.common.BusinessException;
import com.wzcl.app.model.common.CodeMsg;
import com.wzcl.app.model.common.MyPage;
import com.wzcl.app.model.dto.KnowledgePointDto;
import com.wzcl.app.service.GradeService;
import com.wzcl.app.service.KnowledgePointService;
import com.wzcl.app.service.SubjectService;
import com.wzcl.app.service.TopicAndKnowledgePointService;
import com.wzcl.app.utils.SpringUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Log4j2
@Service
@Transactional
public class KnowledgePointServiceImpl implements KnowledgePointService {

    @Autowired
    private SubjectService subjectService;

    @Autowired
    private GradeService gradeService;

    @Autowired
    private KnowledgePointRepository repository;

    @Autowired
    private TopicAndKnowledgePointService topicAndKnowledgePointService;

    @Override
    @CacheEvict(value = "KnowledgePoint", allEntries = true)
    public KnowledgePoint saveKnowledgePoint(KnowledgePoint knowledgePoint) {
        return repository.save(knowledgePoint);
    }

    @Override
    @CacheEvict(value = "KnowledgePoint", allEntries = true)
    public KnowledgePoint updateKnowledgePoint(KnowledgePointDto knowledgePointDto) {
        //校验获取
        KnowledgePoint knowledgePoint = getAndCheckById(knowledgePointDto);
        //修改
        knowledgePoint.setChapter(knowledgePointDto.getChapter());
        knowledgePoint.setPoint(knowledgePointDto.getPoint());
        return repository.save(knowledgePoint);
    }

    @Override
    @CacheEvict(value = "KnowledgePoint", allEntries = true)
    public KnowledgePoint delKnowledgePointById(Integer id) {
        //校验获取
        KnowledgePoint knowledgePoint = getAndCheckById(id);
        //删除知识点之前需要手动维护中间表数据
        topicAndKnowledgePointService.unBind(knowledgePoint);
        //删除对应数据
        log.info("KnowledgePoint:{} Physical deletion", JSON.toJSONString(knowledgePoint));
        repository.delete(knowledgePoint);
        return knowledgePoint;
    }

    @Override
    @Cacheable(value = "KnowledgePoint", keyGenerator = "cacheKeyGenerator")
    public KnowledgePoint getKnowledgePointById(Integer id) {
        return repository.findById(id).orElse(null);
    }


    @Override
    @Cacheable(value = "KnowledgePoint", keyGenerator = "cacheKeyGenerator")
    public KnowledgePoint getAndCheckById(Integer id) {
        if (id == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少知识点Id");
        }
        KnowledgePoint knowledgePoint = getKnowledgePointById(id);
        if (knowledgePoint == null) {
            throw new BusinessException(CodeMsg.KNOWLEDGE_POINT_NOT_EXIST);
        }
        return knowledgePoint;
    }

    @Override
    @Cacheable(value = "KnowledgePoint", keyGenerator = "cacheKeyGenerator")
    public KnowledgePoint findByProperty(KnowledgePointDto knowledgePointDto) {
        KnowledgePoint knowledgePoint = repository.findByGradeIdAndSubjectIdAndChapterAndPoint(knowledgePointDto.getGradeId(), knowledgePointDto.getSubjectId(), knowledgePointDto.getChapter(), knowledgePointDto.getPoint());
        if (knowledgePoint == null) {
            //获取年级和学科
            Subject subject = subjectService.getAndCheckById(knowledgePointDto.getSubjectId());
            Grade grade = gradeService.getAndCheckById(knowledgePointDto.getGradeId());
            //创建
            knowledgePoint = new KnowledgePoint();
            knowledgePoint.setSubjectId(subject.getId());
            knowledgePoint.setSubjectName(subject.getName());
            knowledgePoint.setGradeId(grade.getId());
            knowledgePoint.setGradeName(grade.getName());
            knowledgePoint.setChapter(knowledgePointDto.getChapter());
            knowledgePoint.setPoint(knowledgePointDto.getPoint());
            KnowledgePointService knowledgePointService = (KnowledgePointService) SpringUtil.getBean("knowledgePointServiceImpl");
            knowledgePoint = knowledgePointService.saveKnowledgePoint(knowledgePoint);
        }
        return knowledgePoint;
    }

    @Override
    @Cacheable(value = "KnowledgePoint", keyGenerator = "cacheKeyGenerator")
    public List<KnowledgePoint> getKnowledgePointList(KnowledgePointDto knowledgePointDto) {
        return repository.findAll(getSpecification(knowledgePointDto), knowledgePointDto.getSort());
    }

    @Override
    public List<KnowledgePoint> getKnowledgePointByTopicId(Integer topicId) {
        return topicAndKnowledgePointService.findKnowledgePointByTopicId(topicId);
    }

    @Override

    public MyPage<KnowledgePoint> getKnowledgePointPage(KnowledgePointDto knowledgePointDto) {
        Page<KnowledgePoint> all = repository.findAll(getSpecification(knowledgePointDto), knowledgePointDto.getPageable());
        ArrayList<KnowledgePoint> list = new ArrayList<>(all.getContent());
        Collections.reverse(list);
        MyPage<KnowledgePoint> myPage = new MyPage<>();
        myPage.setContent(list);
        myPage.setTotalElements(all.getTotalElements());
        return myPage;
    }

    private Specification<KnowledgePoint> getSpecification(KnowledgePointDto knowledgePointDto) {
        return new Specification<KnowledgePoint>() {
            @Override
            public Predicate toPredicate(Root<KnowledgePoint> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (knowledgePointDto.getGradeId() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("gradeId"), knowledgePointDto.getGradeId()));
                }
                if (knowledgePointDto.getSubjectId() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("subjectId"), knowledgePointDto.getSubjectId()));
                }
                if (StringUtils.isNotBlank(knowledgePointDto.getChapter())) {
                    predicates.add(criteriaBuilder.like(root.get("chapter"), "%" + knowledgePointDto.getChapter() + "%"));
                }
                if (StringUtils.isNotBlank(knowledgePointDto.getPoint())) {
                    predicates.add(criteriaBuilder.like(root.get("point"), "%" + knowledgePointDto.getPoint() + "%"));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }
}
